#include <stdio.h>
#include "ice.h"
#include "scheduler.h"


Ice_t Ice;

Ice_t::CommandEntry Ice_t::commands[] = {
	{Ice_t::command_help, "help", 0, 1, 
	"Displays help about the given command or all commands"},
	{Ice_t::command_showcps, "showcps", 0, 0, 
	"Enables CPS measurements"},
	{Ice_t::command_hidecps, "hidecps", 0, 0, 
	"Disables CPS measurements"},
	{Ice_t::command_break, "break", 0, 0, 
	"Triggers a debugger"},
	{Ice_t::command_resume, "resume", 0, 0, 
	"Leaves the MCI and resumes normal execution"},
	{Ice_t::command_quit, "exit", 0, 0, 
	"Quits the program"},
	{Ice_t::command_quit, "quit", 0, 0, 
	"Quits the program"},
	{NULL, NULL, 0, 0, NULL}
};


Ice_t::Ice_t()
{
	m_active = false;
	next_tick = 0;
	SetConsoleCtrlHandler(EventHandler, TRUE);
}

BOOL WINAPI Ice_t::EventHandler(DWORD evnt)
{
	if (evnt == CTRL_C_EVENT) {
		if (!Ice.m_active) {
			Scheduler.Register((schedproc_t)Debugger, &Ice, 0, NULL);
		}
		return TRUE;
	}
	else if (evnt == CTRL_BREAK_EVENT) {
		if (!Ice.m_active) {
			Scheduler.Stop();
			return TRUE;
		}
		return FALSE;
	}
	else {
		return FALSE;
	}
}

bool Ice_t::Debugger(Ice_t& self)
{
	CommandEntry ce;
	int i;
	int tokcount;
	char buf[257];
	char * tokens[257];
	char * c;
	char * last;
	char ch;
	
	self.m_active = true;
	printf("-----------------------------------------------\n" 
	       "           MACHINE CONTROL INTERFACE\n"
	       "-----------------------------------------------\n");
	
	while (self.m_active) {
		//
		// get user input
		//
		printf(">>> ");
		buf[0] = 0;
		if (fgets(buf, 250, stdin) == NULL) {
			printf("\n");
			continue;
		}
		
		//
		// parse
		//
		tokcount = 0;
		for (c = last = buf; ; c++) {
			ch = *c;
			if (ch == 0) {
				break;
			}
			else if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
				*c = 0;
				last = c+1;
			}
			else if (last != NULL) {
				tokens[tokcount] = last;
				tokcount++;
				last = NULL;
			}
		}
		if (tokcount == 0) {
			continue;
		}
		strlwr(tokens[0]);
		
		//
		// dispatch
		//
		for (i = 0; ; i++) {
			ce = commands[i];
			if (ce.func == NULL) {
				printf("Invalid command '%s'\n", tokens[0]);
				break;
			}
			if (strcmp(tokens[0], ce.name) == 0) {
				tokcount--;
				if (tokcount < ce.minargs || (tokcount > ce.maxargs && ce.maxargs != -1)) {
					if (ce.minargs == ce.maxargs) {
						printf("Command requires %d args\n", ce.minargs);
					}
					else {
						printf("Command requires %d to %d args\n", ce.minargs, ce.maxargs);
					}
				}
				else {
					ce.func(self, tokcount, (const char**)tokens+1);
				}
				break;
			}
		}
	}
	printf("-----------------------------------------------\n");
	self.m_active = false;
	
	return false;
}

bool Ice_t::Statistics(Ice_t& self)
{
	DWORD tick = GetTickCount();
	
	if (tick > self.next_tick) {
		printf("[CPS: %d]\n", Scheduler.cycles);
		Scheduler.cycles = 0;
		self.next_tick = tick + 1000;
	}
	
	return self.m_statistics_enabled;
}

void Ice_t::command_resume(Ice_t& self, int argcount, const char ** args)
{
	self.m_active = false;
}

void Ice_t::command_quit(Ice_t& self, int argcount, const char ** args)
{
	Scheduler.Stop();
	self.m_active = false;
}

void Ice_t::command_help(Ice_t& self, int argcount, const char ** args)
{
	CommandEntry ce;
	int i;
	
	if (argcount == 1) {
		printf("Help on command '%s':\n", args[0]);
		for (i = 0; ; i++) {
			ce = commands[i];
			if (ce.func == NULL) {
				printf("No such command\n");
				break;
			}
			if (strcmp(args[0], ce.name)==0) {
				printf("    %s\n", ce.help);
				break;
			}
		}
	}
	else {
		printf("Help on all commands:\n");
		for (i = 0; ; i++) {
			ce = commands[i];
			if (ce.func == NULL) {
				break;
			}
			printf("    %s: %s\n", ce.name, ce.help);
		}
	}
}

void Ice_t::command_showcps(Ice_t& self, int argcount, const char ** args)
{
	if (!self.m_statistics_enabled) {
		self.m_statistics_enabled = true;
		Scheduler.Register((schedproc_t)Statistics, &self, StatisticsInterval);
	}
}

void Ice_t::command_hidecps(Ice_t& self, int argcount, const char ** args)
{
	self.m_statistics_enabled = false;
}

void Ice_t::command_break(Ice_t& self, int argcount, const char ** args)
{
	DebugBreak();
}








